<template>
  <div class="map-container">
    <!-- 顶部操作区 -->
    <div class="top-operation">
      <div class="city-choose">{{ city }}</div>

      <!-- 城市搜索框 -->
      <el-input
        v-model="searchCity"
        placeholder="请输入城市名搜索"
        prefix-icon="Search"
        @keyup.enter="handleSearchCity"
      />

      <!-- 图形绘制选择器 -->
      <el-select v-model="drawType" placeholder="选择绘图类型" @change="handleDrawType">
        <el-option
          v-for="item in options"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>

      <!-- 标记类型选择器 -->
      <el-select
        v-model="iconType"
        placeholder="选择标记类型"
        :disabled="zoom < 13"
        @change="handleIconType"
      >
        <el-option
          v-for="item in icons"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />
      </el-select>
    </div>

    <!-- 地图容器 -->
    <div id="map-container"></div>

    <!-- 弹窗内容 -->
    <div id="popup" v-html="popupContent"></div>
  </div>
</template>

<script setup>
import { onMounted, ref } from 'vue'
import { Search } from '@element-plus/icons-vue'
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import XYZ from 'ol/source/XYZ'
import VectorSource from 'ol/source/Vector'
import GeoJSON from 'ol/format/GeoJSON'
import Style from 'ol/style/Style'
import Fill from 'ol/style/Fill'
import Stroke from 'ol/style/Stroke'
import Icon from 'ol/style/Icon'
import Text from 'ol/style/Text'
import CircleStyle from 'ol/style/Circle'
import Draw from 'ol/interaction/Draw'
import Feature from 'ol/Feature'
import Point from 'ol/geom/Point'
import Overlay from 'ol/Overlay'
import Cluster from 'ol/source/Cluster'
import { getLength, getArea } from 'ol/sphere'
import { transform } from 'ol/proj'

// 引入标记图标
import chargeIcon from './assets/charge.png'
import busIcon from './assets/bus.png'
import parkIcon from './assets/park.png'

// 地图基础配置
const view = new View({
  projection: 'EPSG:4326',
  center: [114.25, 30.59],
  zoom: 4,
})

// 底图图层（高德地图）
const gaodeLayer = new TileLayer({
  source: new XYZ({
    url: 'https://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
  }),
})

// 绘图图层
const drawSource = new VectorSource()
const drawLayer = new VectorLayer({
  source: drawSource,
  style: new Style({
    fill: new Fill({ color: 'rgba(255,0,0,0.4)' }),
    stroke: new Stroke({ color: '#000', width: 2 }),
  }),
})

// 标记点数据源
const iconsSource = new Cluster({
  source: new VectorSource(),
  distance: 100,
})

// 标记图层（聚类）
const iconsLayer = new VectorLayer({
  source: iconsSource,
  style: clusterStyle,
})

function clusterStyle(feature) {
  const features = feature.get('features')
  const size = features.length

  if (size === 1) {
    // 单个标记显示对应图标（复原正确逻辑）
    const icon = features[0].get('icon')
    return new Style({
      image: new Icon({
        src: icon,
        scale: 0.8,
      }),
    })
  } else {
    // 多个标记显示聚类圆（修复嵌套错误）
    return new Style({
      image: new CircleStyle({
        radius: 15,
        fill: new Fill({ color: 'rgba(0,0,255,0.7)' }),
      }),
      text: new Text({
        text: size.toString(),
        fill: new Fill({ color: '#fff' }),
        font: '12px sans-serif',
      }),
    })
  }
}

// 响应式数据
const city = ref('定位中...')
const zoom = ref(4)
const adcode = ref('')
const searchCity = ref('')
const popupContent = ref('')
const drawType = ref('')
const iconType = ref('')

// 常量配置
const GAODEKEY = 'c3359c4076630d633d4e57d8fae934eb'
const options = [
  { label: '直线', value: 'LineString' },
  { label: '圆形', value: 'Circle' },
  { label: '多边形', value: 'Polygon' },
  { label: '自由画线', value: 'FreehandLine' }, // 新增自由画线选项
  { label: '退出绘图', value: 'exit' },
]
const icons = [
  { label: '充电站', value: chargeIcon },
  { label: '公交站', value: busIcon },
  { label: '停车场', value: parkIcon },
  { label: '退出标记', value: 'exit' },
]

// 地图实例及图层变量
let map = null
let cityLayer = null
let popup = null
let draw = null

// 组件挂载初始化
onMounted(() => {
  // 初始化地图
  map = new Map({
    target: 'map-container',
    layers: [gaodeLayer, drawLayer, iconsLayer],
    view: view,
  })

  // 初始化弹窗
  popup = new Overlay({
    element: document.getElementById('popup'),
    positioning: 'bottom-center',
    offset: [0, -10],
  })
  map.addOverlay(popup)

  // IP定位获取当前城市
  fetch(`https://restapi.amap.com/v3/ip?key=${GAODEKEY}`)
    .then((res) => res.json())
    .then((data) => {
      if (data.status === '1') {
        city.value = data.city
        adcode.value = data.adcode
        // 延迟加载城市边界（确保adcode已获取）
        setTimeout(() => loadCityBoundary(adcode.value), 1000)
      }
    })

  // 地图点击事件（显示弹窗）
  map.on('click', (event) => {
    const features = map.getFeaturesAtPixel(event.pixel)
    if (features && features.length > 0) {
      const feature = features[0]
      if (feature.get('name')) {
        const coordinate = event.coordinate
        popupContent.value = `
          <div>城市：${feature.get('name')}</div>
          <div>经度：${coordinate[0].toFixed(6)}</div>
          <div>纬度：${coordinate[1].toFixed(6)}</div>
        `
        popup.setPosition(coordinate)
      }
    } else {
      popup.setPosition(undefined)
    }
  })

  // 地图点击添加标记
  map.on('click', (event) => {
    if (iconType.value && iconType.value !== 'exit' && zoom.value >= 13) {
      const feature = new Feature({
        geometry: new Point(event.coordinate),
      })
      feature.set('icon', iconType.value)
      iconsSource.getSource().addFeature(feature)
    }
  })

  // 监听缩放级别变化
  view.on('change:resolution', () => {
    zoom.value = view.getZoom()
    // 控制城市边界和绘图图层显示
    if (cityLayer) {
      cityLayer.setVisible(zoom.value <= 10)
    }
    drawLayer.setVisible(zoom.value <= 10)
  })

  // 监听绘图结束事件（面积计算）
  drawSource.on('addfeature', (event) => {
    const feature = event.feature
    const geometry = feature.getGeometry()
    let area, tooltipContent

    // 转换为墨卡托投影计算
    const geomWebMercator = geometry.clone().transform('EPSG:4326', 'EPSG:3857')

    if (geometry.getType() === 'Circle') {
      // 圆形面积计算（平方米 → 公顷）
      const radius = geomWebMercator.getRadius()
      area = Math.PI * radius * radius
      tooltipContent = `面积：${(area / 10000).toFixed(2)} 公顷`
    } else if (geometry.getType() === 'Polygon') {
      // 多边形面积计算
      area = getArea(geomWebMercator)
      tooltipContent = `面积：${(area / 10000).toFixed(2)} 公顷`
    }

    if (tooltipContent) {
      // 创建面积提示框
      const tooltip = document.createElement('div')
      tooltip.className = 'area-tooltip'
      tooltip.innerHTML = tooltipContent

      // 计算图形中心点
      const center =
        geometry.getType() === 'Circle'
          ? geometry.getCenter()
          : geometry.getInteriorPoint().getCoordinates()

      const areaOverlay = new Overlay({
        element: tooltip,
        position: center,
        positioning: 'center-center',
      })
      map.addOverlay(areaOverlay)

      // 5秒后自动隐藏
      setTimeout(() => map.removeOverlay(areaOverlay), 5000)

      // 鼠标悬停显示/离开隐藏
      feature.on('pointerover', () => map.addOverlay(areaOverlay))
      feature.on('pointerout', () => map.removeOverlay(areaOverlay))
    }
  })
})

// 加载城市边界
const loadCityBoundary = (adcode) => {
  fetch(`https://geo.datav.aliyun.com/areas_v3/bound/${adcode}.json`)
    .then((res) => res.json())
    .then((data) => {
      // 移除旧边界图层
      if (cityLayer) {
        map.removeLayer(cityLayer)
      }
      // 创建新边界图层
      cityLayer = new VectorLayer({
        source: new VectorSource({
          features: new GeoJSON().readFeatures(data),
        }),
        style: new Style({
          stroke: new Stroke({ color: '#ff0000', width: 2 }),
          fill: new Fill({ color: 'rgba(255,0,0,0.1)' }),
        }),
        className: 'city-layer',
      })
      map.addLayer(cityLayer)
      // 定位到城市
      const extent = cityLayer.getSource().getExtent()
      view.fit(extent, { duration: 2000, padding: [100, 100, 100, 100] })
    })
}

// 城市搜索
const handleSearchCity = () => {
  if (!searchCity.value) return
  // 高德地理编码接口
  fetch(`https://restapi.amap.com/v3/geocode/geo?address=${searchCity.value}&key=${GAODEKEY}`)
    .then((res) => res.json())
    .then((data) => {
      if (data.status === '1' && data.geocodes.length > 0) {
        const geocode = data.geocodes[0]
        adcode.value = geocode.adcode
        loadCityBoundary(adcode.value)
        city.value = geocode.city
      } else {
        searchCity.value = ''
        alert('未找到该城市，请重新输入')
      }
    })
}

// 绘图类型处理
const handleDrawType = () => {
  // 清除现有绘图交互
  if (draw) {
    map.removeInteraction(draw)
    draw = null
  }

  if (drawType.value === 'exit') {
    drawType.value = ''
    return
  }

  // 处理自由画线（实际类型仍是LineString，但启用freehand）
  const isFreehand = drawType.value === 'FreehandLine'
  const type = isFreehand ? 'LineString' : drawType.value

  // 创建新绘图交互
  draw = new Draw({
    source: drawSource,
    type: type,
    freehand: isFreehand,
    freehandCondition: (event) => isFreehand, // 自由画线模式下始终启用手绘
  })

  // 直线/自由画线添加测距功能
  if (type === 'LineString') {
    let totalLength = 0
    const nodeOverlays = []
    const lengthOverlays = []

    // 顶点添加时实时计算长度
    draw.on('vertexadd', (event) => {
      // 清除现有标记
      nodeOverlays.forEach((overlay) => map.removeOverlay(overlay))
      lengthOverlays.forEach((overlay) => map.removeOverlay(overlay))
      nodeOverlays.length = 0
      lengthOverlays.length = 0

      const geometry = event.feature.getGeometry()
      const coordinates = geometry.getCoordinates()
      totalLength = 0

      // 遍历所有顶点计算长度
      coordinates.forEach((coord, index) => {
        if (index === 0) return

        // 计算线段长度（米）
        const prevCoord = coordinates[index - 1]
        const segmentLength = getLength([prevCoord, coord], { projection: 'EPSG:4326' })
        totalLength += segmentLength

        // 添加顶点标记
        const nodeEl = document.createElement('div')
        nodeEl.className = 'node-marker'
        const nodeOverlay = new Overlay({
          element: nodeEl,
          position: coord,
          positioning: 'center-center',
        })
        map.addOverlay(nodeOverlay)
        nodeOverlays.push(nodeOverlay)

        // 添加累计长度提示
        const midCoord = [(prevCoord[0] + coord[0]) / 2, (prevCoord[1] + coord[1]) / 2]
        const lengthEl = document.createElement('div')
        lengthEl.className = 'length-tooltip'
        lengthEl.innerHTML = `累计：${totalLength.toFixed(1)} 米`
        const lengthOverlay = new Overlay({
          element: lengthEl,
          position: midCoord,
          positioning: 'top-center',
        })
        map.addOverlay(lengthOverlay)
        lengthOverlays.push(lengthOverlay)
      })
    })

    // 绘制结束后清除临时监听
    draw.on('drawend', () => {
      draw.un('vertexadd')
    })
  }

  map.addInteraction(draw)
}

// 标记类型处理
const handleIconType = () => {
  if (zoom.value < 13 && iconType.value !== 'exit') {
    iconType.value = ''
    alert('请放大到13级以上后再标记地图')
  }
}
</script>

<style scoped lang="scss">
#map-container {
  position: absolute;
  top: 80px;
  width: 100%;
  height: calc(100% - 80px);
  z-index: 1;
}

.top-operation {
  height: 80px;
  background-color: #4264fb;
  position: fixed;
  top: 0;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 100px;
  padding: 0 50px;
  z-index: 10;

  .city-choose {
    color: white;
    font-size: 16px;
    margin: 0 50px;
  }

  :deep(.el-input__wrapper) {
    height: 38px;
  }

  :deep(.el-select__wrapper) {
    height: 38px;
  }
}

#popup {
  width: 200px;
  padding: 10px;
  background-color: pink;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
  height: max-content;
}

/* 新增面积提示框样式 */
.area-tooltip {
  background: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  pointer-events: none;
}

/* 新增长度提示框和顶点标记样式 */
.length-tooltip {
  background: rgba(0, 0, 255, 0.7);
  color: white;
  padding: 2px 6px;
  border-radius: 2px;
  font-size: 12px;
  pointer-events: none;
}

.node-marker {
  width: 6px;
  height: 6px;
  background: red;
  border-radius: 50%;
  pointer-events: none;
}
</style>
